package com.gusto.engine.colfil.service.impl;

import java.util.Collection;
import java.util.List;

import org.apache.log4j.Logger;

import com.gusto.engine.colfil.Distance;
import com.gusto.engine.colfil.Evaluation;
import com.gusto.engine.colfil.Prediction;
import com.gusto.engine.colfil.Rating;
import com.gusto.engine.colfil.formula.ItemCorrelation;
import com.gusto.engine.colfil.formula.UserCorrelation;
import com.gusto.engine.colfil.matrix.MatrixDAO;
import com.gusto.engine.colfil.service.CollaborativeService;
import com.gusto.engine.colfil.service.util.DistanceCalculator;

/**
 * <p>Facade for using the collaborative module.</p>
 * 
 * @author amokrane.belloui@gmail.com
 *
 */
public class CollaborativeServiceImpl implements CollaborativeService {
	
	private Logger log = Logger.getLogger(getClass());
	
	private MatrixDAO matrixDAO;
	private DistanceCalculator distanceCalculator;
	
	public void setMatrixDAO(MatrixDAO matrixDAO) {
		this.matrixDAO = matrixDAO;
		this.distanceCalculator.setMatrixDAO(matrixDAO);
	}
	
	public void setUserCorrelation(UserCorrelation userCorrelation) {
		this.distanceCalculator.setUserCorrelation(userCorrelation);
	}
	
	public void setItemCorrelation(ItemCorrelation itemCorrelation) {
		this.distanceCalculator.setItemCorrelation(itemCorrelation);
	}

	public CollaborativeServiceImpl() {
		distanceCalculator = new DistanceCalculator();
	}
	
	public void insertRating(long userId, long itemId, Rating rating, boolean checkExistence) {
		// Insert Rating
		log.info("Inserting rating " + userId + " " + itemId + " => " + rating);
	}
	
	public void insertPrediction(long userId, long itemId, Prediction prediction) {
		// Insert Prediction
		log.info("Inserting prediction " + userId + " " + itemId + " => " + prediction);
	}
	
	public Evaluation getPrediction(long userId, long itemId) {
		Evaluation prediction = matrixDAO.getPrediction(userId, itemId);
		log.info("Getting prediction " + userId + " " + itemId + " => " + prediction);
		return prediction;
	}
	
	public Evaluation getRating(long userId, long itemId) {
		Evaluation rating = matrixDAO.getRating(userId, itemId);
		log.info("Getting rating " + userId + " " + itemId + " => " + rating);
		return rating;
	}
	
	public List<Rating> getItemsRatedByUser(long userId, boolean normalized) {
		return getItemsRatedByUser(userId, normalized);
	}

	public List<Rating> getUsersHavingRatedItem(long itemId, boolean normalized) {
		return getUsersHavingRatedItem(itemId, normalized);
	}
	
	public double getUserMeanRating(long userId) {
		double mean = matrixDAO.getUserMeanRating(userId);
		log.info("User mean " + userId + " " + mean);
		return mean;
	}
	
	public double getItemMeanRating(long itemId) {
		double mean = matrixDAO.getItemMeanRating(itemId);
		log.info("Item mean " + itemId + " " + mean);
		return mean;
	}
	
	public List<Rating> getSubMatrix(Collection<Long> usersIds, Collection<Long> itemsIds) {
		List<Rating> subMatrix = matrixDAO.getSubMatrix(usersIds, itemsIds);
		log.info("SubMatrix contaning " + subMatrix.size());
		return subMatrix;
	}

	public Distance calculateItemDistance(long item1, long item2) {
		return distanceCalculator.calculateItemDistance(item1, item2);
	}

	public Distance calculateUserDistance(long user1, long user2) {
		return distanceCalculator.calculateUserDistance(user1, user2);
	}
	
}
